home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS02.ADF / IFF / showilbm.c < prev    next >
Text File  |  1989-05-30  |  13KB  |  373 lines

  1. /** ShowILBM.c **************************************************************
  2.  *
  3.  * Read an ILBM raster image file and display it.  11/15/85.
  4.  *
  5.  * By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
  6.  * This software is in the public domain.
  7.  *
  8.  * USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER.
  9.  *
  10.  * The IFF reader portion is essentially a recursive-descent parser.
  11.  * This program will look into a CAT or LIST to find a FORM ILBM, but it
  12.  * won't look inside another FORM type for a nested FORM ILBM.
  13.  *
  14.  * The display portion is specific to the Commodore Amiga computer.
  15.  *
  16.  * NOTE: This program displays an image, pauses, then exits. It doesn't
  17.  * bother to switch you back to the CLI or workbench "screen", so type
  18.  * Amiga-N when it's done.
  19.  *
  20.  ****************************************************************************/
  21.  
  22. #include "graphics/system.h"
  23. #include "libraries/dos.h"
  24. #include "iff/ilbm.h"
  25.  
  26. /* This example's max number of planes in a bitmap. Could use MaxAmDepth. */
  27. #define EXDepth 5
  28. #define maxColorReg (1<<EXDepth)
  29. #define MIN(a,b) ((a)<(b)?(a):(b))
  30.  
  31. #define SafeFreeMem(p,q) {if(p)FreeMem(p,q);}
  32.  
  33. /* general usage pointers */
  34. struct GfxBase *GfxBase;
  35.  
  36. /* Globals for displaying an image */
  37. struct RastPort rP;
  38. struct BitMap bitmap;
  39. struct RasInfo rasinfo;
  40. struct View v = {0};
  41. struct ViewPort vp = {0};
  42.     
  43. /* Define the size of a temporary buffer used in unscrambling the ILBM rows.*/
  44. #define bufSz 512
  45.  
  46. /* Message strings for IFFP codes. */
  47. char MsgOkay[]        = { "(IFF_OKAY) No FORM ILBM in the file." };
  48. char MsgEndMark[]     = { "(END_MARK) How did you get this message?" };
  49. char MsgDone[]        = { "(IFF_DONE) All done."};
  50. char MsgDos[]         = { "(DOS_ERROR) The DOS returned an error." };
  51. char MsgNot[]         = { "(NOT_IFF) Not an IFF file." };
  52. char MsgNoFile[]      = { "(NO_FILE) No such file found." };
  53. char MsgClientError[] = { "(CLIENT_ERROR) ShowILBM bug or insufficient RAM."};
  54. char MsgForm[]        = { "(BAD_FORM) A malformed FORM ILBM." };
  55. char MsgShort[]       = { "(SHORT_CHUNK) A malformed FORM ILBM." };
  56. char MsgBad[]         = { "(BAD_IFF) A mangled IFF file." };
  57.  
  58. /* THESE MUST APPEAR IN RIGHT ORDER!! */
  59. char *IFFPMessages[-LAST_ERROR+1] = {
  60.     /*IFF_OKAY*/  MsgOkay,
  61.     /*END_MARK*/  MsgEndMark,
  62.     /*IFF_DONE*/  MsgDone,
  63.     /*DOS_ERROR*/ MsgDos,
  64.     /*NOT_IFF*/   MsgNot,
  65.     /*NO_FILE*/   MsgNoFile,
  66.     /*CLIENT_ERROR*/ MsgClientError,
  67.     /*BAD_FORM*/  MsgForm,
  68.     /*SHORT_CHUNK*/  MsgShort,
  69.     /*BAD_IFF*/   MsgBad
  70.     };
  71.  
  72. /*------------ ILBM reader -----------------------------------------------*/
  73. /* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file.
  74.  * We allocate one of these on the stack for every LIST or FORM encountered
  75.  * in the file and use it to hold BMHD & CMAP properties. We also allocate
  76.  * an initial one for the whole file.
  77.  * We allocate a new GroupContext (and initialize it by OpenRIFF or
  78.  * OpenRGroup) for every group (FORM, CAT, LIST, or PROP) encountered. It's
  79.  * just a context for reading (nested) chunks.
  80.  *
  81.  * If we were to scan the entire example file outlined below:
  82.  *    reading          proc(s)                new               new
  83.  *
  84.  * --whole file--   ReadPicture+ReadIFF   GroupContext        ILBMFrame
  85.  * CAT              ReadICat                GroupContext
  86.  *   LIST           GetLiILBM+ReadIList       GroupContext        ILBMFrame
  87.  *     PROP ILBM    GetPrILBM                   GroupContext
  88.  *       CMAP       GetCMAP
  89.  *       BMHD       GetBMHD
  90.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  91.  *       BODY       GetBODY
  92.  *     FORM ILBM    GetFoILBM                   GroupContext        ILBMFrame
  93.  *       BODY       GetBODY
  94.  *   FORM ILBM      GetFoILBM                 GroupContext        ILBMFrame
  95.  */
  96. typedef struct {
  97.    ClientFrame clientFrame;
  98.    UBYTE foundBMHD;
  99.    UBYTE nColorRegs;
  100.    BitMapHeader bmHdr;
  101.    Color4 colorMap[maxColorReg];
  102.    /* If you want to read any other property chunks, e.g. GRAB or CAMG, add
  103.     * fields to this record to store them. */
  104.    } ILBMFrame;
  105.  
  106.  
  107. /* NOTE: For a simple version of this program, set Fancy to 0.
  108.  * That'll compile a program that skips all LISTs and PROPs in the input
  109.  * file. It will look in CATs for FORMs ILBM. That's suitable for most uses.
  110.  *
  111.  * For a fancy version that handles LISTs and PROPs, set Fancy to 1. */
  112. #define Fancy  0
  113.  
  114.  
  115. /** DisplayPic() ************************************************************
  116.  *
  117.  * Interface to Amiga graphics ROM routines.
  118.  *
  119.  ****************************************************************************/
  120. DisplayPic(ptilbmFrame)  ILBMFrame *ptilbmFrame;  {
  121.     int i;
  122.     struct View *oldView = GfxBase->ActiView;    /* so we can restore it */
  123.  
  124.     InitView(&v);
  125.     InitVPort(&vp);
  126.     v.ViewPort = &vp;
  127.     InitRastPort(&rP);
  128.     rP.BitMap = &bitmap;
  129.     rasinfo.BitMap = &bitmap;
  130.  
  131.     /* Always show the upper left-hand corner of this picture. */
  132.     rasinfo.RxOffset = 0;
  133.     rasinfo.RyOffset = 0;
  134.  
  135.     vp.DWidth = ptilbmFrame->bmHdr.pageWidth;    /* Physical display WIDTH */
  136.     vp.DHeight = ptilbmFrame->bmHdr.pageHeight;    /* Display height */
  137.  
  138. #if 0
  139.     /* Specify where on screen to put the ViewPort. */
  140.     vp.DxOffset = ptilbmFrame->bmHdr.x;
  141.     vp.DyOffset = ptilbmFrame->bmHdr.y;
  142. #else
  143.     /* Always display it in upper left corner of screen.*/
  144. #endif
  145.  
  146.     if (ptilbmFrame->bmHdr.pageWidth <= 320) 
  147.     vp.Modes = 0;
  148.     else vp.Modes = HIRES;
  149.     if (ptilbmFrame->bmHdr.pageHeight > 200) {
  150.     v.Modes |= LACE;
  151.     vp.Modes |= LACE;
  152.     }
  153.     vp.RasInfo = &rasinfo;
  154.     MakeVPort(&v,&vp);
  155.     MrgCop(&v);
  156.     LoadView(&v);    /* show the picture */
  157.     WaitBlit();
  158.     WaitTOF();
  159.     LoadRGB4(&vp, ptilbmFrame->colorMap, ptilbmFrame->nColorRegs);
  160.  
  161.     for (i = 0; i < 5*60; ++i)  WaitTOF();    /* Delay 5 seconds. */
  162.  
  163.     LoadView(oldView);    /* switch back to old view */
  164.     }
  165.  
  166. /** GetFoILBM() *************************************************************
  167.  *
  168.  * Called via ReadPicture to handle every FORM encountered in an IFF file.
  169.  * Reads FORMs ILBM and skips all others.
  170.  * Inside a FORM ILBM, it stops once it reads a BODY. It complains if it
  171.  * finds no BODY or if it has no BMHD to decode the BODY.
  172.  *
  173.  * Once we find a BODY chunk, we'll allocate the BitMap and read the image.
  174.  *
  175.  ****************************************************************************/
  176. IFFP GetFoILBM(parent)  GroupContext *parent;  {
  177.    /*compilerBug register*/ IFFP iffp;
  178.    GroupContext formContext;
  179.    ILBMFrame ilbmFrame;        /* only used for non-clientFrame fields.*/
  180.    register int i;
  181.    int plsize;    /* Plane size in bytes. */
  182.    int nPlanes; /* number of planes in our display image */
  183.    BYTE buffer[bufSz];
  184.  
  185.    if (parent->subtype != ID_ILBM)
  186.       return(IFF_OKAY);    /* just continue scaning the file */
  187.  
  188.    ilbmFrame = *(ILBMFrame *)parent->clientFrame;
  189.    iffp = OpenRGroup(parent, &formContext);
  190.    CheckIFFP();
  191.  
  192.    do switch (iffp = GetFChunkHdr(&formContext)) {
  193.       case ID_BMHD: {
  194.     ilbmFrame.foundBMHD = TRUE;
  195.     iffp = GetBMHD(&formContext, &ilbmFrame.bmHdr);
  196.     break; }
  197.       case ID_CMAP: {
  198.     ilbmFrame.nColorRegs = maxColorReg;  /* we have room for this many */
  199.     iffp = GetCMAP(
  200.        &formContext, (WORD *)&ilbmFrame.colorMap, &ilbmFrame.nColorRegs);
  201.     break; }
  202.       case ID_BODY: {
  203.          if (!ilbmFrame.foundBMHD)  return(BAD_FORM);    /* No BMHD chunk! */
  204.  
  205.      nPlanes = MIN(ilbmFrame.bmHdr.nPlanes, EXDepth);
  206.      InitBitMap(
  207.         &bitmap,
  208.         nPlanes,
  209.         ilbmFrame.bmHdr.w,
  210.         ilbmFrame.bmHdr.h);
  211.      plsize = RowBytes(ilbmFrame.bmHdr.w) * ilbmFrame.bmHdr.h;
  212.      if (bitmap.Planes[0] =
  213.         (PLANEPTR)AllocMem(nPlanes * plsize, MEMF_CHIP))
  214.         {
  215.         for (i = 1; i < nPlanes; i++)
  216.         bitmap.Planes[i] = (PLANEPTR) bitmap.Planes[0] + plsize*i;
  217.         iffp = GetBODY(
  218.         &formContext,
  219.         &bitmap,
  220.         NULL,
  221.         &ilbmFrame.bmHdr,
  222.         buffer,
  223.         bufSz);
  224.         if (iffp == IFF_OKAY) iffp = IFF_DONE;    /* Eureka */
  225.         }
  226.      else 
  227.         iffp = CLIENT_ERROR;    /* not enough RAM for the bitmap */
  228.          break; }
  229.       case END_MARK: { iffp = BAD_FORM; break; } /* No BODY chunk! */
  230.       } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
  231.               * subroutine returned IFF_OKAY (no errors).*/
  232.  
  233.    if (iffp != IFF_DONE)  return(iffp);
  234.  
  235.    /* If we get this far, there were no errors. */
  236.    CloseRGroup(&formContext);
  237.    DisplayPic(&ilbmFrame);
  238.    return(iffp);
  239.    }
  240.  
  241. /** Notes on extending GetFoILBM ********************************************
  242.  *
  243.  * To read more kinds of chunks, just add clauses to the switch statement.
  244.  * To read more kinds of property chunks (GRAB, CAMG, etc.) add clauses to
  245.  * the switch statement in GetPrILBM, too.
  246.  *
  247.  * To read a FORM type that contains a variable number of data chunks--e.g.
  248.  * a FORM FTXT with any number of CHRS chunks--replace the ID_BODY case with
  249.  * an ID_CHRS case that doesn't set iffp = IFF_DONE, and make the END_MARK
  250.  * case do whatever cleanup you need.
  251.  *
  252.  ****************************************************************************/
  253.  
  254. /** GetPrILBM() *************************************************************
  255.  *
  256.  * Called via ReadPicture to handle every PROP encountered in an IFF file.
  257.  * Reads PROPs ILBM and skips all others.
  258.  *
  259.  ****************************************************************************/
  260. #if Fancy
  261. IFFP GetPrILBM(parent)  GroupContext *parent;  {
  262.    /*compilerBug register*/ IFFP iffp;
  263.    GroupContext propContext;
  264.    ILBMFrame *ilbmFrame = (ILBMFrame *)parent->clientFrame;
  265.  
  266.    if (parent->subtype != ID_ILBM)
  267.       return(IFF_OKAY);    /* just continue scaning the file */
  268.  
  269.    iffp = OpenRGroup(parent, &propContext);
  270.    CheckIFFP();
  271.  
  272.    do switch (iffp = GetPChunkHdr(&propContext)) {
  273.       case ID_BMHD: {
  274.     ilbmFrame->foundBMHD = TRUE;
  275.     iffp = GetBMHD(&propContext, &ilbmFrame->bmHdr);
  276.     break; }
  277.       case ID_CMAP: {
  278.     ilbmFrame->nColorRegs = maxColorReg; /* we have room for this many */
  279.     iffp = GetCMAP(
  280.       &propContext, (WORD *)&ilbmFrame->colorMap, &ilbmFrame->nColorRegs);
  281.     break; }
  282.       } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a
  283.               * subroutine returned IFF_OKAY (no errors).*/
  284.  
  285.    CloseRGroup(&propContext);
  286.    return(iffp == END_MARK ? IFF_OKAY : iffp);
  287.    }
  288. #endif
  289.  
  290. /** GetLiILBM() *************************************************************
  291.  *
  292.  * Called via ReadPicture to handle every LIST encountered in an IFF file.
  293.  *
  294.  ****************************************************************************/
  295. #if Fancy
  296. IFFP GetLiILBM(parent)  GroupContext *parent;  {
  297.     ILBMFrame newFrame;    /* allocate a new Frame */
  298.  
  299.     newFrame = *(ILBMFrame *)parent->clientFrame;  /* copy parent frame */
  300.  
  301.     return( ReadIList(parent, (ClientFrame *)&newFrame) );
  302.     }
  303. #endif
  304.  
  305. /** ReadPicture() ***********************************************************
  306.  *
  307.  * Read a picture from an IFF file, given a file handle open for reading.
  308.  *
  309.  ****************************************************************************/
  310. IFFP ReadPicture(file)  LONG file;  {
  311.    ILBMFrame iFrame;    /* Top level "client frame".*/
  312.    IFFP iffp = IFF_OKAY;
  313.  
  314. #if Fancy
  315.    iFrame.clientFrame.getList = &GetLiILBM;
  316.    iFrame.clientFrame.getProp = &GetPrILBM;
  317. #else
  318.    iFrame.clientFrame.getList = &SkipGroup;
  319.    iFrame.clientFrame.getProp = &SkipGroup;
  320. #endif
  321.    iFrame.clientFrame.getForm = &GetFoILBM;
  322.    iFrame.clientFrame.getCat  = &ReadICat ;
  323.  
  324.    /* Initialize the top-level client frame's property settings to the
  325.     * program-wide defaults. This example just records that we haven't read
  326.     * any BMHD property or CMAP color registers yet. For the color map, that
  327.     * means the default is to leave the machine's color registers alone.
  328.     * If you want to read a property like GRAB, init it here to (0, 0). */
  329.    iFrame.foundBMHD  = FALSE;
  330.    iFrame.nColorRegs = 0;
  331.  
  332.    iffp = ReadIFF(file, (ClientFrame *)&iFrame);
  333.  
  334.    Close(file);
  335.    return(iffp);
  336.    }
  337.  
  338. /** main0() *****************************************************************/
  339. void main0(filename)  char *filename;  {
  340.     LONG file;
  341.     IFFP iffp = NO_FILE;
  342.  
  343.     /* load and display the picture */
  344.     if( !(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)) )
  345.     exit(0);
  346.     file = Open(filename, MODE_OLDFILE);
  347.     if (file)
  348.     iffp = ReadPicture(file);
  349.  
  350.     printf(" %s\n", IFFPMessages[-iffp]);
  351.  
  352.     /* cleanup */
  353.     if (bitmap.Planes[0])  {
  354.     FreeMem(bitmap.Planes[0],
  355.         bitmap.BytesPerRow * bitmap.Rows * bitmap.Depth);
  356.     FreeVPortCopLists(&vp);
  357.     FreeCprList(v.LOFCprList);
  358.     }
  359.     CloseLibrary(GfxBase);
  360.     }
  361.  
  362. /** main() ******************************************************************/
  363. void main(argc, argv)  int argc;  char **argv;  {
  364.     printf("Showing file '%s' ...", argv[1]);
  365.     if (argc < 2)
  366.     printf("\nUsage: 'ShowILBM filename'");
  367.     else
  368.     main0(argv[1]);
  369.     printf("\n");
  370.     exit(0);
  371.     }
  372.  
  373.